package com.dayang.redbook.auth.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.dayang.framework.biz.context.holder.LoginUserContextHolder;
import com.dayang.framework.common.domain.response.Response;
import com.dayang.framework.common.exception.BizException;
import com.dayang.redbook.auth.constant.RedisConstants;
import com.dayang.redbook.auth.enums.LoginTypeEnum;
import com.dayang.redbook.auth.exception.ResponseCodeEnum;
import com.dayang.redbook.auth.model.user.vo.UpdatePasswordReqVO;
import com.dayang.redbook.auth.model.user.vo.UserLoginReqVO;
import com.dayang.redbook.auth.rpc.UserRpcService;
import com.dayang.redbook.auth.service.AuthService;
import com.dayang.redbook.user.dto.resp.FindUserByPhoneRspDTO;
import com.google.common.base.Preconditions;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
 * @author: dayang
 * @since: 2024/5/31
 * @description:
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {
    private final RedisTemplate<String, Object> redisTemplate;
    private final PasswordEncoder passwordEncoder;
    private final UserRpcService userRpcService;

    /**
     * 登录与注册
     * @param userLoginReqVO 用户登录参数
     * @return
     */
    @Override
    public Response<String> loginAndRegister(UserLoginReqVO userLoginReqVO) {
        String phone = userLoginReqVO.getPhone();
        Integer type = userLoginReqVO.getType();
        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(type);
        Long userId = null;
        switch (loginTypeEnum){
            case VERIFICATION_CODE:
                String verificationCode = userLoginReqVO.getCode();
                Preconditions.checkArgument(StrUtil.isNotBlank(verificationCode), "验证码不能为空");
                String key = RedisConstants.buildVerificationCodeKey(phone);
                String sendCode = (String) redisTemplate.opsForValue().get(key);
                if (!StrUtil.equals(verificationCode,sendCode)){
                    throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_ERROR);
                }
                // RPC: 调用用户微服务，注册用户
                Long userIdTmp = userRpcService.registerUser(phone);
                // 若调用用户服务，返回的用户 ID 为空，则提示登录失败
                if (Objects.isNull(userIdTmp)) {
                    throw new BizException(ResponseCodeEnum.LOGIN_FAIL);
                }
                userId = userIdTmp;
                break;
            case PASSWORD:
                String password = userLoginReqVO.getPassword();
                // RPC: 调用用户服务，通过手机号查询用户
                FindUserByPhoneRspDTO findUserByPhoneRspDTO = userRpcService.findUserByPhone(phone);
                if (Objects.isNull(findUserByPhoneRspDTO)){
                    throw new BizException(ResponseCodeEnum.USER_NOT_FOUND);
                }
                String encodePassword = findUserByPhoneRspDTO.getPassword();
                boolean isMatch = passwordEncoder.matches(password, encodePassword);
                if (!isMatch){
                    throw new BizException(ResponseCodeEnum.PHONE_OR_PASSWORD_ERROR);
                }
                userId = findUserByPhoneRspDTO.getId();
                break;
            default:
                break;
        }
        StpUtil.login(userId);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return Response.success(tokenInfo.tokenValue);
    }

    /**
     * 退出登录
     *
     * @return
     */
    @Override
    public Response<?> logout() {
        Long userId = LoginUserContextHolder.getUserId();
        log.info("==> 用户退出登录, userId: {}", userId);
        StpUtil.logout(userId);
        return Response.success();
    }

    /**
     * 修改密码
     * @param updatePasswordReqVO 新密码
     * @return
     */
    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
        String newPassword = updatePasswordReqVO.getNewPassword();
        String encodePassword = passwordEncoder.encode(newPassword);
        // RPC: 调用用户服务：更新密码
        userRpcService.updatePassword(encodePassword);
        return Response.success();
    }
}
